package string;
/*1.java会将所有使用字面量(直接量)形式创建的字符串对象缓存在常量池中
 * 每当使用相同字面量形式创建字符串时，会重用对象以减少内存开销
 * 2.new String()创建时，一定会创建新对象，不会在常量池中有
 * 3.String是不变对象，创建后内容不可改变
 * 4.若想比较字符串内容相同，需要使用equals()方法*/

public class StringDemo {
    public static void main(String[] args) {
        String s1 = "123abc";//字面量创建的字符串第一次使用会缓存在常量池中
        String s2 = "123abc";//重用s1对象(重用常量池中"123abc"对象)
        String s3 = "123abc";
        System.out.println(s1 == s2);//true，s1和s2为引用类型变量，保存的是地址，两个地址相同
        System.out.println(s1 == s3);
        String s4 = new String("123abc");//new则一定创建新对象，但不推荐
        System.out.println(s4 == s1);

        s1 = s1 + "!";//字符串是不变对象，修改内容会创建新的对象
        System.out.println(s2 == s1);//false,地址不同，意味着不再指向同一个对象

        String s = "123";
        String s5 = s + "abc";//这里编译器不做操作，拼接字符串会产生新对象。s是个变量
        System.out.println(s5 == s2);//false,没有重用常量池对象

        String s6 = "123" + "abc";//触发计算特性，直接编译为String s5 ="123abc",会复用该对象
        System.out.println(s6 == s2);//true

        /*
         * ==是比较值是否相等，对于引用类型而言，引用中保存的是地址，
         * 所以--比较的也是地址，地址相同意味着两个引用指向了同一个对象
         * 对于字符串而言，实际应用中我们通常希望比较的是两个字符串的内容是否相同
         * 因此对于字符串而言，一般是通过equals()来比较字符串内容是否相同的
         * */
        String s7 = "123abc";
        String s8 = new String("123abc");
        /*在执行String s8 = new String("123abc");时，会创建两个对象。下面来详细分析：
字符串常量对象：当在代码里使用双引号创建字符串"123abc"时，Java 会先去字符串常量池查找是否存在内容为123abc的字符串。
要是不存在，就会在字符串常量池创建一个123abc字符串对象。
堆内存中的字符串对象：new String()这种构造方式会在 Java 堆内存中创建一个新的字符串对象。
这个新对象是对字符串常量池里123abc对象的复制。
综上所述，这行代码总共创建了两个字符串对象，一个在字符串常量池，另一个在堆内存中。*/
        System.out.println(s7 == s8);//false  ==是比较地址，因为地址不同所以为false
        System.out.println(s7.equals(s8));//true  .equals()是比较内容相同的
        //1. String类、包装类重写了equals()来比较内容是否相等，但StringBuilder并没有。


    }
}
